import { ReqUser } from '@common/auth';
import { PublicUrl } from '@common/utils/constants';
import { ensureDir, writeFile } from 'fs-extra';
import { extname, join } from 'path';
import { ObjectId, Types } from 'mongoose';
// 使用策略模式上传文件

interface IUpload {
    upload(reqUser: ReqUser, files: Express.Multer.File[], objectId?: ObjectId): Promise<string[]>;
}

// 用户头像上传策略
class UserAvatarUpload implements IUpload {
    async upload(reqUser: ReqUser, files: Express.Multer.File[]) {
        const dirUrl = join(PublicUrl, 'img', 'user', 'avatar', reqUser._id);
        await ensureDir(dirUrl);
        const file = files[0];
        // extname 后缀
        const fileName = Date.now() + extname(file.originalname);
        await writeFile(join(dirUrl, `${fileName}`), file.buffer);
        // todo 先这么写
        return [`img/user/avatar/${reqUser._id}/${fileName}`];
    }
}

// 用户作品上传
class UserPhotosUpload implements IUpload {
    async upload(reqUser: ReqUser, files: Express.Multer.File[], objectId?: ObjectId) {
        if (!objectId) {
            throw new Error('upload need objectId');
        }
        const dirUrl = join(PublicUrl, 'img', 'user', 'photos', reqUser._id, String(objectId));
        await ensureDir(dirUrl);
        const now = Date.now();
        await Promise.all(
            files.map((file, index) => {
                const fileName = `${now}_${index}${extname(file.originalname)}`;
                return writeFile(join(dirUrl, `${fileName}`), file.buffer);
            })
        );
        return files.map(
            (file, index) =>
                `img/user/photos/${reqUser._id}/${String(objectId)}/${now}_${index}${extname(
                    file.originalname
                )}`
        );
    }
}

export enum UploadStrategy {
    USER_AVATAR_UPLOAD,
    USER_PHOTOS_UPLOAD,
}
export class FileUpload implements IUpload {
    private _upload: IUpload = new UserAvatarUpload();

    constructor(strategy: UploadStrategy) {
        this.setStrategy(strategy);
    }

    async upload(reqUser: ReqUser, files: Express.Multer.File[], objectId?: ObjectId) {
        const res = await this._upload.upload(reqUser, files, objectId);
        return res.map(it => `${process.env.COMMON_SERVER_URI}/${it}`);
        // return `${process.env.COMMON_SERVER_URI}/${res}`;
    }
    // 客户端通过此方法设置不同的策略
    setStrategy(strategy: UploadStrategy) {
        switch (strategy) {
            case UploadStrategy.USER_AVATAR_UPLOAD:
                this._upload = new UserAvatarUpload();
                break;
            case UploadStrategy.USER_PHOTOS_UPLOAD:
                this._upload = new UserPhotosUpload();
                break;
            default:
                throw new Error("There's no such strategy yet.");
        }
    }
}
